package EA.testEAs;
import EA.*;
import EA.testproblems.*;
import EA.operators.selection.*;
import EA.recording.*;
import java.util.Hashtable;
import java.util.Arrays;
import RKUjava.datastructures.RKUVector;
import RKUjava.util.*;
import RKUjava.lang.*;
import RKUjava.math.*;
import Visualization.plot.*;

/** Implements a sharing GA. It is possible to run the GA with either bit 
    representation or realvector representation.
    The following is a simple implementation of the main class.<br>
    <pre>
    import EA.*;
    import EA.testproblems.*;
    import EA.testEAs.SharingGA;
    
    public class sharingga
    {
      &nbsp;&nbsp;static NumericalProblem curproblem;
      &nbsp;&nbsp;static SharingGA sga;
      &nbsp;&nbsp;static BatchJobScheduler BJS;
    
      &nbsp;&nbsp;public static void main(String argv[])
        &nbsp;&nbsp;{
	  &nbsp;&nbsp;&nbsp;&nbsp;if (argv.length==0){
	    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((new SharingGA()).getDefaultSettings());
	    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(0);
	  &nbsp;&nbsp;&nbsp;&nbsp;}
	  &nbsp;&nbsp;&nbsp;&nbsp;curproblem = new UrsemMultimodal1();
  	  &nbsp;&nbsp;&nbsp;&nbsp;sga = new SharingGA(curproblem);
	  &nbsp;&nbsp;&nbsp;&nbsp;BJS = new BatchJobScheduler(sga);
	  &nbsp;&nbsp;&nbsp;&nbsp;BJS.startScheduler(argv);
	  &nbsp;&nbsp;&nbsp;&nbsp;System.exit(0);
        &nbsp;&nbsp;}
    }</pre>

    @see EA.BitNumericalGenome
    @see EA.RealNumericalGenome
*/
public class SharingGA implements BatchJobEA
{

  /** Representation type. (Default = 0)<br>
      0 = Realvalue vectors with RealNumericalGenome.<br>
      1 = Bitrepresented vectors with BitNumericalGenome.<br>
  */
  public int representationtype = 0;

  /** The current problem. */
  public NumericalProblem curproblem;

  /** The current framework. */
  public NumericalFramework nf;
    
  /** Create a sharing GA.<br><b>Note:</b> Remember to set curproblem. */
  public SharingGA()
    {
      super();
    }

  /** Create a sharing GA with the given problem. */
  public SharingGA(NumericalProblem aproblem)
    {
      super();
      curproblem = aproblem;
    }

  // **** BatchJob implementation *****************************

  /** Set the settings for the algorithm. The passed hashtable contains
      only String objects which are all related to the input file given 
      to the scheduler. 
  */
  public void setSettings(Hashtable settings)
    {
      String curstr;

      if ((curstr = (String)settings.get("representationtype"))!=null) {
	representationtype = (new Integer(curstr)).intValue();
      }

      switch (representationtype) {
      case 0:
	nf = new RealSharingGAFramework(curproblem);
	((RealSharingGAFramework)nf).theGA = this;
	break;
      case 1:
	nf = new BitSharingGAFramework(curproblem);
	((BitSharingGAFramework)nf).theGA = this;
	break;
      }
      ((BatchJobEA)nf).setSettings(settings);

    };

  /** Get the default settings in the BatchJobScheduler format. This 
      method can be used to reconstruct an input file for the scheduler. 
  */
  public String getDefaultSettings()
    {
      RealSharingGAFramework f = new RealSharingGAFramework();
      StringBuffer res = new StringBuffer();

      res.append(BatchJobScheduler.getDefaultSettings());
      res.append("#################################################################\n");
      res.append("# ------------- Algorithmic settings ----------------------------\n");
      res.append("# Save fitness statistics\n");
      res.append("savefitnessstats = "+f.savefitnessstats+"\n");
      res.append("\n");
      res.append("# Save score statistics (See Multinational papers)\n");
      res.append("savescorestats = "+f.savescorestats+"\n");
      res.append("\n");
      res.append("# Save distance statistics\n");
      res.append("savediststats = "+f.savediststats+"\n");
      res.append("\n");
      res.append("# Datasampling: How often should data be stored for output\n");
      res.append("datasampling = "+f.datasampling+"\n");
      res.append("\n");
      res.append("# Print information to stdout (true/false)\n");
      res.append("verbose = "+f.verbose+"\n");
      res.append("\n");
      res.append("# Representation type\n");
      res.append("#  0 = Real valued vectors (RealNumericalGenome).\n");
      res.append("#  1 = Binary encoded vectors (BitNumericalGenome).\n");
      res.append("representationtype = "+representationtype+"\n");
      res.append("\n");
      res.append("# Number of bits per variable if binary encoding is used\n");      
      res.append("bitspervar = 30\n");
      res.append("\n");
      res.append("# Probability for mutation\n");
      res.append("p_m = "+f.p_m+"\n");
      res.append("\n");
      res.append("# Mutation variance (only used on dynamic problems)\n");
      res.append("mutationvariance = "+f.mutationvariance+"\n");
      res.append("\n");
      res.append("# Probability for crossover\n");
      res.append("p_c = "+f.p_c+"\n");
      res.append("\n");
      res.append("# Maximal number of iterations\n");
      res.append("maxiterations = "+f.maxiterations+"\n");
      res.append("\n");
      res.append("# Initial number of individuals\n");
      res.append("initialpopsize = "+f.initialpopsize+"\n");
      res.append("\n");
      res.append("# Iteration multiplier can be used to multiply maxiterations so more iterations\n");
      res.append("# are run. This can be used when comparing algorithms with more fitness \n");
      res.append("# evaluations per generation. (E.g. multinational GA)\n");
      res.append("# Besides running more iterations it also change the generations from \n");
      res.append("# natural numbers to decimal.\n");
      res.append("# Example: If iterationmultiplier = 5 and maxiterations = 200, then 1000 generations\n");
      res.append("# will be performed and in the output files the generation column will contain\n");
      res.append("# 0.0, 0.2, 0.4, 0.6, ..., 198.8, 199.0\n");
      res.append("# This is simply to help gnuplot\n");
      res.append("iterationmultiplier = "+f.iterationmultiplier+"\n");
      res.append("\n");
      res.append("# Sigma share (see Handbook on EC section C6.1)\n");
      res.append("sigma_share = "+f.sigma_share+"\n");
      res.append("\n");
      res.append("# Alpha (see Handbook on EC section C6.1)\n");
      res.append("alpha = "+f.alpha+"\n");
      res.append("\n");

      return res.toString();
    };

  /** Initialize a batchjob. This is called once before any run is performed.
   */
  public void initializeBatchJobs()
    {
    };

  /** Finalize a batchjob. This is called once after all runs are performed.
   */
  public void finalizeBatchJobs()
    {
      ((BatchJobEA)nf).finalizeBatchJobs();
    };

  /** Initialize a run series. This is called once before the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void initializeRunSeries()
    {
      ((BatchJobEA)nf).initializeRunSeries();
    };

  /** Finalize a run series. This is called once after the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void finalizeRunSeries()
    {
      ((BatchJobEA)nf).finalizeRunSeries();
    };

  /** Initialize and start a single run of the algorithm. You can 
      usually just call doEA() from your framework.
  */
  public void initializeAndStartRun()
    {
      ((BatchJobEA)nf).initializeAndStartRun();
    };

  /** Finalize the single run of the algorithm. This is called immediately
      after the initializeAndStartRun(). It can be used to reset 
      measurements, increase counters, etc.
  */
  public void finalizeRun()
    {
      ((BatchJobEA)nf).finalizeRun();
    };

  /** Get the run data as text. Your implementation must return
      an array of objects that each implements the interface ConvertToText from the package
      EA.recording. You can use the classes found in EA.recording or 
      implement your own classes.
      @see EA.recording.ConvertToText
  */
  public Object[] getDataAsText()
    {
      return ((BatchJobEA)nf).getDataAsText();
    };
}



class RealSharingGAFramework extends RealNumericalFramework implements BatchJobEA, DataPlot2DExtraction
{

  // True if the info should be printed to stdout
  boolean verbose;

  public boolean savefitnessstats = true;

  public boolean savescorestats = false;

  public boolean savediststats = false;

  public boolean savetablestats = false;

  public boolean elitism = false;

  public int datasampling = 1;

  // Probability for mutation
  public double p_m = 0.75;
    
  public double mutationvariance = 0.5;

  // Probability for crossover
  public double p_c = 0.9;

  // Maximal number of iterations
  public int maxiterations = 200;
    
  // Initial number of individuals
  public int initialpopsize = 100;

  public int iterationmultiplier = 1;

  // Is this problem a maximization problem.
  public boolean ismaximization = true;

  public boolean isdynamicproblem = false;

  public NumericalProblem curproblem;

  public SharingGAIndividual[] population;

  public SharingGA theGA;

  public double sigma_share = 0.2;

  public double alpha = 1;

  public int displaygraph = 0, displaybest = 0;

  private SequenceTable results1, scoretable1, disttable1;

  int iterationrounder = 1;

  // Helper variables
  double[] bestdists;
  int currentdatasample = 0;	

  int[] top5mincnt;
  int[] top5maxcnt;

  int[] toppeaksmax = null;
  int[] toppeaksmin = null;

  /** Helper Comparator for sorting peaks. */
  RKUComparator maximalpeaks = new  RKUComparator()
    {
      RealSharingGAFramework framework;

      public void initialize(Object o1, Object o2)
      {
	framework = (RealSharingGAFramework)o1;
      }

      public int compare(Object o1, Object o2)
      {
	NumericalOptimum o1opt =(NumericalOptimum)o1;
	NumericalOptimum o2opt =(NumericalOptimum)o2;
	double o1fit = o1opt.getFitness();
	double o2fit = o2opt.getFitness();
      
	if (o1fit>o2fit) return -1;
	else if (Math.abs(o1fit-o2fit)<0.00001) {
	  if (top5maxcnt[o1opt.optimumindex]>top5maxcnt[o2opt.optimumindex]) {
	    return -1;
	  }
	  else if (top5maxcnt[o1opt.optimumindex]==top5maxcnt[o2opt.optimumindex]) {
	    return 0;
	  }
	  else {
	    return 1;
	  }
	}
	else return 1;
      }
    };

  /** Helper Comparator for sorting peaks. */
  RKUComparator minimalpeaks = new  RKUComparator(this)
    {
      RealSharingGAFramework framework;

      public void initialize(Object o1, Object o2)
      {
	framework = (RealSharingGAFramework)o1;
      }

      public int compare(Object o1, Object o2)
      {
	NumericalOptimum o1opt =(NumericalOptimum)o1;
	NumericalOptimum o2opt =(NumericalOptimum)o2;
	double o1fit = o1opt.getFitness();
	double o2fit = o2opt.getFitness();
      
	if (o1fit<o2fit) return -1;
	else if (Math.abs(o1fit-o2fit)<0.00001) {
	  if (top5mincnt[o1opt.optimumindex]>top5mincnt[o2opt.optimumindex]) {
	    return -1;
	  }
	  else if (top5mincnt[o1opt.optimumindex]==top5mincnt[o2opt.optimumindex]) {
	    return 0;
	  }
	  else {
	    return 1;
	  }
	}
	else return 1;
      }
    };




  /** Create a new framework. */
  public RealSharingGAFramework()
    {
      super();
    }

  /** Create a new framework. */
  public RealSharingGAFramework(NumericalProblem numproblem)
    {
      super(numproblem);
      curproblem = numproblem;
      ismaximization = curproblem.ismaximization;
    }

  public void Framework_doEA_inner()
    {
      preserveElite();
      statistics();
      recombine();
      alter();
      selection();
      evaluate();
      keepElite();

      if (isdynamicproblem) {
	if (iteration%iterationmultiplier == 0) {
	  ((DynamicNumericalProblem)curproblem).updateProblem();
	}
      }
    }

  public void statistics() 
    {
      int bestindex;
      int i,j;
      double curdist, bestdist, curfit;
      NumericalOptimum curoptimum;
      String iterationstr;
      double foundmin = 0, foundmax = 0, topfoundmin = 0, topfoundmax = 0, popscore = 0, toppopscore = 0;

      // check if we should sample now?
      if (currentdatasample<datasampling-1 && iteration!=0) {
	currentdatasample++;
	return;
      }
      currentdatasample = 0;	

      if (iterationmultiplier>1) {
	iterationstr = RKUStringUtils.decimalFormatter(((double)iteration)/iterationmultiplier,iterationrounder);
      }
      else {
	iterationstr = ""+iteration;
      }

      bestindex = PopulationMeasurements.indexOfBest(population, ismaximization);

      if (savefitnessstats) {
	results1.initializeRow();
	results1.updateLastRow(0,iterationstr);
	results1.updateLastRow(1,population[bestindex].getFitness());
	results1.updateLastRow(2,population[bestindex].getPos());
	results1.updateLastRow(2+curproblem.dimensions, PopulationMeasurements.calcMean(population));
	results1.updateLastRow(3+curproblem.dimensions, PopulationMeasurements.calcStandardDeviation(population));
      }

      if (savescorestats) {
	popscore = (100*calcPopulationScore())/calcOptimalScore(0);
	toppopscore = (100*calcTopPopulationScore(5))/calcOptimalScore(5);
	//System.out.println("popscore="+popscore+" topscore="+toppopscore);
	foundmax = calcFoundMaximum();
	foundmin = calcFoundMinimum();
	topfoundmax = calcTopFoundMaximum(5);
	topfoundmin = calcTopFoundMinimum(5);

      }


      if (savescorestats) {
	scoretable1.initializeRow();
	scoretable1.updateLastRow(0,iterationstr);
	scoretable1.updateLastRow(1,curproblem.objectivefunction.currentevals);
	scoretable1.updateLastRow(2, popscore);
	scoretable1.updateLastRow(3, toppopscore);
	if (ismaximization) {
	  scoretable1.updateLastRow(4, foundmax);
	  scoretable1.updateLastRow(5, topfoundmax);
	}
	else {
	  scoretable1.updateLastRow(4, foundmin);
	  scoretable1.updateLastRow(5, topfoundmin);
	}

	scoretable1.updateLastRow(6, population[bestindex].getFitness());
      }

      if (savediststats) {
	disttable1.initializeRow();
	disttable1.updateLastRow(0,iterationstr);
	disttable1.updateLastRow(1,curproblem.objectivefunction.currentevals);

	curoptimum = curproblem.getGlobalOptimum();

	if (curproblem!=null) {
	  
	  for (i=0;i<bestdists.length;i++) {
	    bestdists[i] = Double.POSITIVE_INFINITY;
	  }

	  if (ismaximization) {
	    for (i=0;i<population.length;i++) {
	      for (j=0;j<bestdists.length;j++) {
		curdist = RKUGeometry.distancePoint2Point(curproblem.knownmaxima[j].getPos(),population[i].getPos());
		if (curdist<bestdists[j]) {
		  bestdists[j] = curdist;
		}
	      }
	    }
	  }
	  else {
	    for (i=0;i<population.length;i++) {
	      for (j=0;j<bestdists.length;j++) {
		curdist = RKUGeometry.distancePoint2Point(curproblem.knownminima[j].getPos(),population[i].getPos());
		if (curdist<bestdists[j]) {
		  bestdists[j] = curdist;
		}
	      }
	    }
	  }

	  disttable1.updateLastRow(2, bestdists[curoptimum.optimumindex]);

	  for (j=0;j<bestdists.length;j++) {
	    disttable1.updateLastRow(3+j, bestdists[j]);
	  }
	}
      }



      if (verbose)
	System.out.println("Bestfit="+population[bestindex].getFitness());

      if (savetablestats) {
	curfit = population[bestindex].getFitness();

	if (ismaximization && table_bestfit<curfit)
	  table_bestfit = curfit;
	else if (!ismaximization && table_bestfit>curfit)
	  table_bestfit = curfit;

	if (ismaximization && table_foundpeaks<foundmax)
	  table_foundpeaks = foundmax;
	else if (!ismaximization && table_foundpeaks<foundmin)
	  table_foundpeaks = foundmin;

	if (ismaximization && table_topfoundpeaks<topfoundmax)
	  table_topfoundpeaks = topfoundmax;
	else if (!ismaximization && table_topfoundpeaks<topfoundmin)
	  table_topfoundpeaks = topfoundmin;
      };


    }

  public double table_foundpeaks;
  public double table_topfoundpeaks;
  public double table_bestfit;


  // Helper methods for statistics.
  double findpercentage_threshold = 0.05;

  public double calcOptimalScore(int peaks)
    {
      double optimalscore = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;

      if (ismaximization) {
	if (peaks==0)
	  numberofpeaks = curproblem.knownmaxima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownmaxima.length);
      }
      else {
	if (peaks==0)
	  numberofpeaks = curproblem.knownminima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownminima.length);
      }

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 100.0;
      
      for (i=0;i<popsize;i++) {
	optimalscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - i/numberofpeaks));
      }
      return optimalscore;
    }

  public double calcPopulationScore()
    {
      double popscore = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] maxcnt, mincnt;
      NumericalOptimum curoptimum;
      int curindex;

      if (ismaximization)
	numberofpeaks = curproblem.knownmaxima.length;
      else 
	numberofpeaks = curproblem.knownminima.length;

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      maxcnt = new int[curproblem.knownmaxima.length];
      mincnt = new int[curproblem.knownminima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];

	if (ismaximization)
	  curoptimum = curproblem.getClosestFoundMaximum(curind.getPos());
	else
	  curoptimum = curproblem.getClosestFoundMinimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - maxcnt[curindex]));
	    maxcnt[curindex] +=1;
	  }
	  else {
	    curindex = curoptimum.optimumindex;
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - mincnt[curindex]));
	    mincnt[curindex] +=1;
	  }
	}
      }

      return popscore;
    }

  int[] toppeaks = null;

  public double calcTopPopulationScore(int peaks)
    {
      double popscore = 0;
      int numberofpeaks;
      int i,j,k;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] maxcnt, mincnt;
      NumericalOptimum curoptimum;
      int curindex;

      if (ismaximization) {
	if (peaks==0)
	  numberofpeaks = curproblem.knownmaxima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownmaxima.length);
      }
      else {
	if (peaks==0)
	  numberofpeaks = curproblem.knownminima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownminima.length);
      }

      if (isdynamicproblem || toppeaks == null) {
	toppeaks = new int[numberofpeaks];
	for (i=0;i<numberofpeaks;i++) {
	  toppeaks[i] = -1;
	}

	if (ismaximization) {
	  for(i = 0;i<curproblem.knownmaxima.length;i++) {
	    j = 0;
	    while (j<numberofpeaks) {
	      if (toppeaks[j]==-1 || curproblem.knownmaxima[i].getFitness()>curproblem.knownmaxima[toppeaks[j]].getFitness()) {
		for (k=numberofpeaks-1;k>j;k--) {
		  toppeaks[k] = toppeaks[k-1];
		}
		toppeaks[j] = i;
		j = numberofpeaks;
	      }
	      j++;
	    }
	  }
	}
	else {
	  for(i = 0;i<curproblem.knownminima.length;i++) {
	    j = 0;
	    while (j<numberofpeaks) {
	      if (toppeaks[j]==-1 || curproblem.knownminima[i].getFitness()<curproblem.knownminima[toppeaks[j]].getFitness()) {
		for (k=numberofpeaks-1;k>j;k--) {
		  toppeaks[k] = toppeaks[k-1];
		}
		toppeaks[j] = i;
		j = numberofpeaks;
	      }
	      j++;
	    }
	  }
	}
      }


      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      maxcnt = new int[curproblem.knownmaxima.length];
      mincnt = new int[curproblem.knownminima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];
	if (ismaximization)
	  curoptimum = curproblem.getClosestFoundMaximum(curind.getPos());
	else
	  curoptimum = curproblem.getClosestFoundMinimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    maxcnt[curindex] +=1;
	  }
	  else {
	    curindex = curoptimum.optimumindex;
	    mincnt[curindex] +=1;
	  }
	}
      }

      if (ismaximization) {
	for (i=0;i<numberofpeaks;i++) {
	  for (j=0;j<maxcnt[toppeaks[i]];j++) {
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - j));
	  }
	}
      }
      else {
	for (i=0;i<numberofpeaks;i++) {
	  for (j=0;j<mincnt[toppeaks[i]];j++) {
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - j));
	  }
	}
	
      }

      return popscore;
    }



  /** Calculate the number of found peaks. A peak is only found if at least 10%
      of the population is near it. */
  public double calcFoundMaximum()
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] maxcnt;
      NumericalOptimum curoptimum;
      int curindex;

      numberofpeaks = curproblem.knownmaxima.length + curproblem.knownminima.length;
      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      maxcnt = new int[curproblem.knownmaxima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    maxcnt[curindex] +=1;
	  }
	}
      }

      for (i=0;i<maxcnt.length;i++) {
	if (maxcnt[i]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }

  /** Calculate the number of found peaks. A peak is only found if at least 10%
      of the population is near it. */
  public double calcFoundMinimum()
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] mincnt;
      NumericalOptimum curoptimum;
      int curindex;

      numberofpeaks = curproblem.knownmaxima.length + curproblem.knownminima.length;
      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      mincnt = new int[curproblem.knownminima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (!curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    mincnt[curindex] +=1;
	  }
	}
      }

      for (i=0;i<mincnt.length;i++) {
	if (mincnt[i]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }

  /** Calculate the number of found top peaks. A peak is only found if at least 5%
      of the population is near it. */
  public double calcTopFoundMaximum(int peaks)
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i,j,k;
      int popsize = population.length;
      SharingGAIndividual curind;
      NumericalOptimum curoptimum;
      int curindex;
      NumericalOptimum[] optima;
      RKUVector tmpvec;

      if (peaks==0)
	numberofpeaks = curproblem.knownmaxima.length;
      else
	numberofpeaks = Math.min(peaks,curproblem.knownmaxima.length);

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;
      
      for (i=0;i<top5maxcnt.length;i++) {
	top5maxcnt[i] = 0;
      }

      for (i=0;i<popsize;i++) {
	curind = (SharingGAIndividual)population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    top5maxcnt[curindex] +=1;
	  }
	}
      }

      if (toppeaksmax==null) {
      	toppeaksmax = new int[numberofpeaks];
      }

      tmpvec = new RKUVector();
      tmpvec.addArray(curproblem.knownmaxima);
      tmpvec.quickSort(maximalpeaks);

      for (i=0;i<numberofpeaks;i++) {
	curoptimum = (NumericalOptimum)tmpvec.elementAt(i);
	toppeaksmax[i] = curoptimum.optimumindex;
      }

      for (i=0;i<toppeaksmax.length;i++) {
	if (top5maxcnt[toppeaksmax[i]]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }

  /** Calculate the number of found top peaks. A peak is only found if at least 5%
      of the population is near it. */
  public double calcTopFoundMinimum(int peaks)
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i,j,k;
      int popsize = population.length;
      SharingGAIndividual curind;
      NumericalOptimum curoptimum;
      int curindex;
      NumericalOptimum[] optimas;
      RKUVector tmpvec;

      if (peaks==0)
	numberofpeaks = curproblem.knownminima.length;
      else
	numberofpeaks = Math.min(peaks,curproblem.knownminima.length);

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;
      
      for (i=0;i<top5mincnt.length;i++) {
	top5mincnt[i] = 0;
      }

      for (i=0;i<popsize;i++) {
	curind = (SharingGAIndividual)population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (!curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    top5mincnt[curindex] +=1;
	  }
	}
      }

      if (toppeaksmin==null) {
      	toppeaksmin = new int[numberofpeaks];
      }

      tmpvec = new RKUVector();
      tmpvec.addArray(curproblem.knownminima);
      tmpvec.quickSort(minimalpeaks);

      for (i=0;i<numberofpeaks;i++) {
	curoptimum = (NumericalOptimum)tmpvec.elementAt(i);
	toppeaksmin[i] = curoptimum.optimumindex;
	//	System.out.println("Peak "+toppeaksmin[i]+" fit="+curproblem.knownminima[toppeaksmin[i]].getFitness()+" psize="+top5mincnt[toppeaksmin[i]]);
      }

      for (i=0;i<toppeaksmin.length;i++) {
	if (top5mincnt[toppeaksmin[i]]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }



  public boolean terminate()
    {
      return iteration<(maxiterations-1)*iterationmultiplier;
    }

  public void Framework_initialize_inner()
    {
      int i;
      population = new SharingGAIndividual[initialpopsize];

      currentdatasample = 0;

      for (i = 0;i<initialpopsize;i++) {
	population[i] = new SharingGAIndividual(this, true, theGA.representationtype);
      };

      ismaximization = curproblem.ismaximization;

      if (ismaximization) 
	bestdists = new double[curproblem.knownmaxima.length];
      else
	bestdists = new double[curproblem.knownminima.length];

      top5maxcnt = new int[curproblem.knownmaxima.length];
      top5mincnt = new int[curproblem.knownminima.length];

      results1 = null;
      if (savefitnessstats) {
	results1 = new SequenceTable("sharingfitness");
	results1.addColumn(new SequenceTableColumn("Generation"));
	results1.addColumn(new SequenceTableColumn("Bestfit"));
	results1.addColumns(curproblem.getSequenceTableColumns(""));
	results1.addColumn(new SequenceTableColumn("Mean"));
	results1.addColumn(new SequenceTableColumn("Std deviation"));
      }

      scoretable1 = null;
      if (savescorestats) {
	  scoretable1 = new SequenceTable("scores");
	  scoretable1.addColumn(new SequenceTableColumn("Generation"));
	  scoretable1.addColumn(new SequenceTableColumn("Evaluations"));
	  scoretable1.addColumn(new SequenceTableColumn("Score")); 
	  scoretable1.addColumn(new SequenceTableColumn("Top 5 Score")); 
	  scoretable1.addColumn(new SequenceTableColumn("# Peaks"));
	  scoretable1.addColumn(new SequenceTableColumn("# Top 5 Peaks"));
	  scoretable1.addColumn(new SequenceTableColumn("Best fit"));
      }	  

      disttable1 = null;
      if (savediststats) {
	  disttable1 = new SequenceTable("dists");
	  disttable1.addColumn(new SequenceTableColumn("Generation"));
	  disttable1.addColumn(new SequenceTableColumn("Evaluations"));
	  disttable1.addColumn(new SequenceTableColumn("Dist2global"));

	  if (ismaximization) {
	    for (i=0;i<curproblem.knownmaxima.length;i++) {
	      disttable1.addColumn(new SequenceTableColumn("DIST "+i));
	    }
	  }
	  else {
	    for (i=0;i<curproblem.knownminima.length;i++) {
	      disttable1.addColumn(new SequenceTableColumn("DIST "+i));
	    }
	  }
      }

      if (isdynamicproblem)
	((DynamicNumericalProblem)curproblem).resetProblem();

      if (savetablestats) {
	table_topfoundpeaks = 0;
	table_foundpeaks = 0;
	if (ismaximization)
	  table_bestfit = Double.NEGATIVE_INFINITY;
	else
	  table_bestfit = Double.POSITIVE_INFINITY;
      };


      // Calc iterationrounder
      if (iterationmultiplier == 1 || iterationmultiplier == 2 ||
	  iterationmultiplier == 5 || iterationmultiplier == 10) {
	iterationrounder = 1;
      }
      else if (iterationmultiplier == 3 || iterationmultiplier == 4 ||
	       iterationmultiplier == 9) {
	iterationrounder = 2;
      }
      else if (iterationmultiplier == 6 || iterationmultiplier == 7 ||
	       iterationmultiplier == 8) {
	iterationrounder = 3;
      }
      else {
	iterationrounder = 3;
      }

      evaluate();
    };

  /** BETA style inner call for summarize().
   */
  public void Framework_summarize_inner()
    {
      statistics();
    }



  RKUComparator coordsort = new  RKUComparator()
    {

      public int compare(Object o1, Object o2)
      {
	SharingGAIndividual ind1, ind2;
	double c1, c2;

	ind1 = (SharingGAIndividual)o1;
	ind2 = (SharingGAIndividual)o2;
	c1 = ((NumericalGenome)ind1.genome).getCoordinateValue(0);
	c2 = ((NumericalGenome)ind2.genome).getCoordinateValue(0);

	if (c1<c2)
	  return -1;
	else if (c1==c2)
	  return 0;
	else
	  return 1;
      }
    };


  /** Override this in your implementation. */
  public void selection()
    {
      SharingGAIndividual[] newpop = new SharingGAIndividual[initialpopsize];
      double sharingfactor, dist;
      int i, j;
      double[] thispos, otherpos;
      double xdist;

      // Sort on first coordinate
      Arrays.sort(population,coordsort);

      for (i = 0;i<population.length;i++) {
	sharingfactor = 0;
	thispos = population[i].getPos();

	sharingfactor += 1 - Math.pow(0/sigma_share, alpha);

	// Calc for individuals to the "left"
	j=i-1;
	xdist = 0;
	while (xdist<sigma_share && j>=0) {
	  otherpos = population[j].getPos();
	  xdist = Math.abs(thispos[0] - otherpos[0]);

	  if (xdist<sigma_share) {
	    dist = RKUGeometry.distancePoint2Point(thispos, otherpos);
	    if (dist<sigma_share)
	      sharingfactor += 1 - Math.pow(dist/sigma_share, alpha);
	  }
	  j--;
	}

	// Calc for individuals to the "right"
	j=i+1;
	xdist = 0;
	while (xdist<sigma_share && j<population.length) {
	  otherpos = population[j].getPos();
	  xdist = Math.abs(thispos[0] - otherpos[0]);

	  if (xdist<sigma_share) {
	    dist = RKUGeometry.distancePoint2Point(thispos, otherpos);
	    if (dist<sigma_share)
	      sharingfactor += 1 - Math.pow(dist/sigma_share, alpha);
	  }
	  j++;
	}

	if (ismaximization) 
	  population[i].fitnessvalue = population[i].getFitness()/sharingfactor;
	else
	  population[i].fitnessvalue = population[i].getFitness()*sharingfactor;

	//	System.out.println(population[i].fitnessvalue+" fit="+population[i].getFitness()+"  sf="+sharingfactor);
      }

      TournamentSelection.selectInto(population, initialpopsize, ismaximization, true, newpop);
      population = newpop;
    };

  SharingGAIndividual[] parents = new SharingGAIndividual[2];

  /* Perform crossover on nations. */
  public void recombine()
    {
      int i;
      SharingGAIndividual[] newpop;
      newpop = new SharingGAIndividual[initialpopsize];

      for (i = 0;i<initialpopsize;i++) {
	if (UsefulRoutines.randomBiasedBoolean(p_c)) {
	  RandomSelection.selectInto(population, 2, ismaximization, false, parents);
	  newpop[i] = parents[0].crossover(parents[0], parents[1]);
	}
	else
	  newpop[i] = (SharingGAIndividual)population[i].clone();
      }
      population = newpop;
    }

  /** Mutate all individuals. */
  public void alter()
    {
      int i;
      double curmut;

      if (!isdynamicproblem) {
	curmut = 1.0/(Math.pow((double)iteration,0.75));
      }
      else {
	curmut = mutationvariance;
      }

      for (i = 0; i<initialpopsize;i++) {
	population[i].mutate(p_m, curmut);
      }
    } 

  /** Evaluate all individuals. */
  public void evaluate()
    {
      double fitsum;
      int i;

      fitsum = 0;

      for (i = 0; i<initialpopsize;i++) {
	fitsum += population[i].getFitness();
      }
      //	System.out.println("Fitsum = "+fitsum);
    }

  SharingGAIndividual eliteIndividual;

  public void preserveElite()
    {
      if (elitism) {
	eliteIndividual = (SharingGAIndividual)(population[PopulationMeasurements.indexOfBest(population, ismaximization)]).clone();
      }
    }

  public void keepElite()
    {
      int pos;
      if (elitism) {
	pos = RKURandom.randomInt(population.length);
	population[pos] = eliteIndividual;
      }
    }


  // **** BatchJob implementation *****************************

  /** Set the settings for the algorithm. The passed hashtable contains
      only String objects which are all related to the input file given 
      to the scheduler. 
  */
  public void setSettings(Hashtable settings)
    {
      String curstr;
      NumericalProblem lcurproblem = null;

      if ((curstr = (String)settings.get("verbose"))!=null) {
	verbose = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savefitnessstats"))!=null) {
	savefitnessstats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savescorestats"))!=null) {
	savescorestats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savediststats"))!=null) {
	savediststats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savetablestats"))!=null) {
	savetablestats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("elitism"))!=null) {
	elitism = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("datasampling"))!=null) {
	datasampling = (new Double(curstr)).intValue();
      }

      if( (curstr = (String)settings.get("p_m"))!=null) {
	p_m = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("mutationvariance"))!=null) {
	mutationvariance = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("p_c"))!=null) {
	p_c = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("sigma_share"))!=null) {
	sigma_share = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("alpha"))!=null) {
	alpha = (new Double(curstr)).doubleValue();
      }

      if ((curstr = (String)settings.get("maxiterations"))!=null) {
	maxiterations = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("initialpopsize"))!=null) {
	initialpopsize = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("iterationmultiplier"))!=null) {
	iterationmultiplier = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("displaygraph"))!=null) {
	displaygraph = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("problemname"))!=null) {
	lcurproblem = NumericalProblemSelector.selectProblem(curstr);
      }
      else {
	lcurproblem = curproblem;
      }

      if (lcurproblem!=null && lcurproblem instanceof DynamicNumericalProblem) {
	isdynamicproblem = true;
	((DynamicNumericalProblem)lcurproblem).setSettings(settings, this);
      }
      else
	isdynamicproblem = false;

      theGA.curproblem = lcurproblem;
      setProblem(lcurproblem);
      curproblem = lcurproblem;

      if (curproblem.dimensions==2 && ((curstr = (String)settings.get("displaybest"))!=null)) {
	displaybest = (new Integer(curstr)).intValue();
      }
    };

  /** Get the default settings in the BatchJobScheduler format. This 
      method can be used to reconstruct an input file for the scheduler. 
  */
  public String getDefaultSettings()
    {
      return "";
    };

  /** Initialize a batchjob. This is called once before any run is performed.
   */
  public void initializeBatchJobs()
    {
    };

  /** Finalize a batchjob. This is called once after all runs are performed.
   */
  public void finalizeBatchJobs()
    {
    };

  /** Initialize a run series. This is called once before the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void initializeRunSeries()
    {};

  /** Finalize a run series. This is called once after the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void finalizeRunSeries()
    {};

  /** Initialize and start a single run of the algorithm. You can 
      usually just call doEA() from your framework.
  */
  public void initializeAndStartRun()
    {
      doEA();
    };

  /** Finalize the single run of the algorithm. This is called immediately
      after the initializeAndStartRun(). It can be used to reset 
      measurements, increase counters, etc.
  */
  public void finalizeRun()
    {
    };

  /** Get the run data as text. Your implementation must return
      an array of objects that each implements the interface ConvertToText from the package
      EA.recording. You can use the classes found in EA.recording or 
      implement your own classes.
      @see EA.recording.ResultSet
      @see EA.recording.Measurement
      @see EA.recording.ConvertToText
  */
  public Object[] getDataAsText()
    {
      Object[] res;
      RKUVector resvec= new RKUVector();

      if (savefitnessstats) {
	resvec.addElement(results1);
      }

      if (savescorestats) {
	resvec.addElement(scoretable1);
      }

      if (savediststats) {
	resvec.addElement(disttable1);
      }

      if (savetablestats) {
	SequenceTable tabletable1 = new SequenceTable("table");
	tabletable1.addColumn(new SequenceTableColumn("Bestfit"));
	tabletable1.addColumn(new SequenceTableColumn("Found peaks"));
	tabletable1.addColumn(new SequenceTableColumn("Top 5 found"));
	tabletable1.initializeRow();

	tabletable1.updateLastRow(0, table_bestfit);
	tabletable1.updateLastRow(1, table_foundpeaks);
	tabletable1.updateLastRow(2, table_topfoundpeaks);

	resvec.addElement(tabletable1);
      }

      res = resvec.toArray();
      return res;
    };

  // ************* Plot interface **********************************

  /** Extract the data as a 2 dimensional array of objects. <br>
      <b>Note:</b> All second-indexes arrays must have equal length.
  */
  public Object[][] extract2DAsObjects(int plotternumber)
    {
      Object[][] res = new Object[2][0];
      switch (plotternumber) {
      case 0:
	res[0] = (results1.getColumn(1)).getDataAsArray();
	res[1] = (results1.getColumn(2+curproblem.dimensions)).getDataAsArray();
	break;
      case 1:
	res[0] = (results1.getColumn(2)).getDataAsArray();
	res[1] = (results1.getColumn(3)).getDataAsArray();
	break;
      }	    
      return res;
    };

  /** Extract the data as a 2 dimensional array of doubles.<br>
      <b>Note:</b> All second-indexes arrays must have equal length. */
  public double[][] extract2DAsDoubles(int plotternumber)
    {
      return null;
    };

  int[][] resultstypes = {{0,0},{0,0}};
  int[][] trajectorytypes = {{2,0},{2,0}};

  public int[][] extract2DDataTypes(int plotternumber)
    {
      switch(plotternumber)
	{
	case 0:
	  return resultstypes;
	case 1: 
	  return trajectorytypes;
	}
      return resultstypes;
    };

  /** Extract the name of a graph given an index. */
  public String extract2DName(int index, int plotternumber)
    {
      switch (plotternumber) {
      case 0:
	switch(index) {
	case 0:
	  return "Bestfit";
	case 1:
	  return "Mean";
	}
	break;
      case 1:
	return "Best pos";
      }
      return "";
    };


}


// ####################################################################
// ####################################################################
// ##### Bit sharing framework ########################################
// ####################################################################
// ####################################################################


class BitSharingGAFramework extends BitNumericalFramework implements BatchJobEA, DataPlot2DExtraction
{

  // True if the info should be printed to stdout
  boolean verbose;

  public boolean savefitnessstats = true;

  public boolean savescorestats = false;

  public boolean savediststats = false;

  public boolean savetablestats = false;

  public boolean elitism = false;

  public int datasampling = 1;

  public int bitspervar = 30;

  // Probability for mutation
  public double p_m = 0.75;
    
  public double mutationvariance = 0.5;

  // Probability for crossover
  public double p_c = 0.9;

  // Maximal number of iterations
  public int maxiterations = 200;
    
  // Initial number of individuals
  public int initialpopsize = 100;

  public int iterationmultiplier = 1;

  // Is this problem a maximization problem.
  public boolean ismaximization = true;

  public boolean isdynamicproblem = false;

  public NumericalProblem curproblem;

  public SharingGAIndividual[] population;

  public SharingGA theGA;

  public double sigma_share = 0.2;

  public double alpha = 1;

  public int displaygraph = 0, displaybest = 0;

  private SequenceTable results1, scoretable1, disttable1;

  int iterationrounder = 1;

  // Helper variables
  double[] bestdists;
  int currentdatasample = 0;	

  int[] top5mincnt;
  int[] top5maxcnt;

  int[] toppeaksmax = null;
  int[] toppeaksmin = null;

  /** Helper Comparator for sorting peaks. */
  RKUComparator maximalpeaks = new  RKUComparator()
    {
      BitSharingGAFramework framework;

      public void initialize(Object o1, Object o2)
      {
	framework = (BitSharingGAFramework)o1;
      }

      public int compare(Object o1, Object o2)
      {
	NumericalOptimum o1opt =(NumericalOptimum)o1;
	NumericalOptimum o2opt =(NumericalOptimum)o2;
	double o1fit = o1opt.getFitness();
	double o2fit = o2opt.getFitness();
      
	if (o1fit>o2fit) return -1;
	else if (Math.abs(o1fit-o2fit)<0.00001) {
	  if (top5maxcnt[o1opt.optimumindex]>top5maxcnt[o2opt.optimumindex]) {
	    return -1;
	  }
	  else if (top5maxcnt[o1opt.optimumindex]==top5maxcnt[o2opt.optimumindex]) {
	    return 0;
	  }
	  else {
	    return 1;
	  }
	}
	else return 1;
      }
    };

  /** Helper Comparator for sorting peaks. */
  RKUComparator minimalpeaks = new  RKUComparator(this)
    {
      BitSharingGAFramework framework;

      public void initialize(Object o1, Object o2)
      {
	framework = (BitSharingGAFramework)o1;
      }

      public int compare(Object o1, Object o2)
      {
	NumericalOptimum o1opt =(NumericalOptimum)o1;
	NumericalOptimum o2opt =(NumericalOptimum)o2;
	double o1fit = o1opt.getFitness();
	double o2fit = o2opt.getFitness();
      
	if (o1fit<o2fit) return -1;
	else if (Math.abs(o1fit-o2fit)<0.00001) {
	  if (top5mincnt[o1opt.optimumindex]>top5mincnt[o2opt.optimumindex]) {
	    return -1;
	  }
	  else if (top5mincnt[o1opt.optimumindex]==top5mincnt[o2opt.optimumindex]) {
	    return 0;
	  }
	  else {
	    return 1;
	  }
	}
	else return 1;
      }
    };




  /** Create a new framework. */
  public BitSharingGAFramework()
    {
      super();
    }

  /** Create a new framework. */
  public BitSharingGAFramework(NumericalProblem numproblem)
    {
      super();
      this.setProblem(numproblem);
      curproblem = numproblem;
      ismaximization = curproblem.ismaximization;
    }

  public void Framework_doEA_inner()
    {
      preserveElite();
      statistics();
      recombine();
      alter();
      selection();
      evaluate();
      keepElite();

      if (isdynamicproblem) {
	if (iteration%iterationmultiplier == 0) {
	  ((DynamicNumericalProblem)curproblem).updateProblem();
	}
      }
    }

  public void statistics() 
    {
      int bestindex;
      int i,j;
      double curdist, bestdist, curfit;
      NumericalOptimum curoptimum;
      String iterationstr;
      double foundmin = 0, foundmax = 0, topfoundmin = 0, topfoundmax = 0, popscore = 0, toppopscore = 0;

      // check if we should sample now?
      if (currentdatasample<datasampling-1 && iteration!=0) {
	currentdatasample++;
	return;
      }
      currentdatasample = 0;	

      if (iterationmultiplier>1) {
	iterationstr = RKUStringUtils.decimalFormatter(((double)iteration)/iterationmultiplier,iterationrounder);
      }
      else {
	iterationstr = ""+iteration;
      }

      bestindex = PopulationMeasurements.indexOfBest(population, ismaximization);

      if (savefitnessstats) {
	results1.initializeRow();
	results1.updateLastRow(0,iterationstr);
	results1.updateLastRow(1,population[bestindex].getFitness());
	results1.updateLastRow(2,population[bestindex].getPos());
	results1.updateLastRow(2+curproblem.dimensions, PopulationMeasurements.calcMean(population));
	results1.updateLastRow(3+curproblem.dimensions, PopulationMeasurements.calcStandardDeviation(population));
      }

      if (savescorestats) {
	popscore = (100*calcPopulationScore())/calcOptimalScore(0);
	toppopscore = (100*calcTopPopulationScore(5))/calcOptimalScore(5);
	//System.out.println("popscore="+popscore+" topscore="+toppopscore);
	foundmax = calcFoundMaximum();
	foundmin = calcFoundMinimum();
	topfoundmax = calcTopFoundMaximum(5);
	topfoundmin = calcTopFoundMinimum(5);

      }


      if (savescorestats) {
	scoretable1.initializeRow();
	scoretable1.updateLastRow(0,iterationstr);
	scoretable1.updateLastRow(1,curproblem.objectivefunction.currentevals);
	scoretable1.updateLastRow(2, popscore);
	scoretable1.updateLastRow(3, toppopscore);
	if (ismaximization) {
	  scoretable1.updateLastRow(4, foundmax);
	  scoretable1.updateLastRow(5, topfoundmax);
	}
	else {
	  scoretable1.updateLastRow(4, foundmin);
	  scoretable1.updateLastRow(5, topfoundmin);
	}

	scoretable1.updateLastRow(6, population[bestindex].getFitness());
      }

      if (savediststats) {
	disttable1.initializeRow();
	disttable1.updateLastRow(0,iterationstr);
	disttable1.updateLastRow(1,curproblem.objectivefunction.currentevals);

	curoptimum = curproblem.getGlobalOptimum();

	if (curproblem!=null) {
	  
	  for (i=0;i<bestdists.length;i++) {
	    bestdists[i] = Double.POSITIVE_INFINITY;
	  }

	  if (ismaximization) {
	    for (i=0;i<population.length;i++) {
	      for (j=0;j<bestdists.length;j++) {
		curdist = RKUGeometry.distancePoint2Point(curproblem.knownmaxima[j].getPos(),population[i].getPos());
		if (curdist<bestdists[j]) {
		  bestdists[j] = curdist;
		}
	      }
	    }
	  }
	  else {
	    for (i=0;i<population.length;i++) {
	      for (j=0;j<bestdists.length;j++) {
		curdist = RKUGeometry.distancePoint2Point(curproblem.knownminima[j].getPos(),population[i].getPos());
		if (curdist<bestdists[j]) {
		  bestdists[j] = curdist;
		}
	      }
	    }
	  }

	  disttable1.updateLastRow(2, bestdists[curoptimum.optimumindex]);

	  for (j=0;j<bestdists.length;j++) {
	    disttable1.updateLastRow(3+j, bestdists[j]);
	  }
	}
      }



      if (verbose)
	System.out.println("Bestfit="+population[bestindex].getFitness());

      if (savetablestats) {
	curfit = population[bestindex].getFitness();

	if (ismaximization && table_bestfit<curfit)
	  table_bestfit = curfit;
	else if (!ismaximization && table_bestfit>curfit)
	  table_bestfit = curfit;

	if (ismaximization && table_foundpeaks<foundmax)
	  table_foundpeaks = foundmax;
	else if (!ismaximization && table_foundpeaks<foundmin)
	  table_foundpeaks = foundmin;

	if (ismaximization && table_topfoundpeaks<topfoundmax)
	  table_topfoundpeaks = topfoundmax;
	else if (!ismaximization && table_topfoundpeaks<topfoundmin)
	  table_topfoundpeaks = topfoundmin;
      };


    }

  public double table_foundpeaks;
  public double table_topfoundpeaks;
  public double table_bestfit;


  // Helper methods for statistics.
  double findpercentage_threshold = 0.05;

  public double calcOptimalScore(int peaks)
    {
      double optimalscore = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;

      if (ismaximization) {
	if (peaks==0)
	  numberofpeaks = curproblem.knownmaxima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownmaxima.length);
      }
      else {
	if (peaks==0)
	  numberofpeaks = curproblem.knownminima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownminima.length);
      }

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 100.0;
      
      for (i=0;i<popsize;i++) {
	optimalscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - i/numberofpeaks));
      }
      return optimalscore;
    }

  public double calcPopulationScore()
    {
      double popscore = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] maxcnt, mincnt;
      NumericalOptimum curoptimum;
      int curindex;

      if (ismaximization)
	numberofpeaks = curproblem.knownmaxima.length;
      else 
	numberofpeaks = curproblem.knownminima.length;

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      maxcnt = new int[curproblem.knownmaxima.length];
      mincnt = new int[curproblem.knownminima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];

	if (ismaximization)
	  curoptimum = curproblem.getClosestFoundMaximum(curind.getPos());
	else
	  curoptimum = curproblem.getClosestFoundMinimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - maxcnt[curindex]));
	    maxcnt[curindex] +=1;
	  }
	  else {
	    curindex = curoptimum.optimumindex;
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - mincnt[curindex]));
	    mincnt[curindex] +=1;
	  }
	}
      }

      return popscore;
    }

  int[] toppeaks = null;

  public double calcTopPopulationScore(int peaks)
    {
      double popscore = 0;
      int numberofpeaks;
      int i,j,k;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] maxcnt, mincnt;
      NumericalOptimum curoptimum;
      int curindex;

      if (ismaximization) {
	if (peaks==0)
	  numberofpeaks = curproblem.knownmaxima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownmaxima.length);
      }
      else {
	if (peaks==0)
	  numberofpeaks = curproblem.knownminima.length;
	else
	  numberofpeaks = Math.min(peaks,curproblem.knownminima.length);
      }

      if (isdynamicproblem || toppeaks == null) {
	toppeaks = new int[numberofpeaks];
	for (i=0;i<numberofpeaks;i++) {
	  toppeaks[i] = -1;
	}

	if (ismaximization) {
	  for(i = 0;i<curproblem.knownmaxima.length;i++) {
	    j = 0;
	    while (j<numberofpeaks) {
	      if (toppeaks[j]==-1 || curproblem.knownmaxima[i].getFitness()>curproblem.knownmaxima[toppeaks[j]].getFitness()) {
		for (k=numberofpeaks-1;k>j;k--) {
		  toppeaks[k] = toppeaks[k-1];
		}
		toppeaks[j] = i;
		j = numberofpeaks;
	      }
	      j++;
	    }
	  }
	}
	else {
	  for(i = 0;i<curproblem.knownminima.length;i++) {
	    j = 0;
	    while (j<numberofpeaks) {
	      if (toppeaks[j]==-1 || curproblem.knownminima[i].getFitness()<curproblem.knownminima[toppeaks[j]].getFitness()) {
		for (k=numberofpeaks-1;k>j;k--) {
		  toppeaks[k] = toppeaks[k-1];
		}
		toppeaks[j] = i;
		j = numberofpeaks;
	      }
	      j++;
	    }
	  }
	}
      }


      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      maxcnt = new int[curproblem.knownmaxima.length];
      mincnt = new int[curproblem.knownminima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];
	if (ismaximization)
	  curoptimum = curproblem.getClosestFoundMaximum(curind.getPos());
	else
	  curoptimum = curproblem.getClosestFoundMinimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    maxcnt[curindex] +=1;
	  }
	  else {
	    curindex = curoptimum.optimumindex;
	    mincnt[curindex] +=1;
	  }
	}
      }

      if (ismaximization) {
	for (i=0;i<numberofpeaks;i++) {
	  for (j=0;j<maxcnt[toppeaks[i]];j++) {
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - j));
	  }
	}
      }
      else {
	for (i=0;i<numberofpeaks;i++) {
	  for (j=0;j<mincnt[toppeaks[i]];j++) {
	    popscore += 1/(1+Math.abs((findpercentage_threshold*popsize)/numberofpeaks - j));
	  }
	}
	
      }

      return popscore;
    }



  /** Calculate the number of found peaks. A peak is only found if at least 10%
      of the population is near it. */
  public double calcFoundMaximum()
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] maxcnt;
      NumericalOptimum curoptimum;
      int curindex;

      numberofpeaks = curproblem.knownmaxima.length + curproblem.knownminima.length;
      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      maxcnt = new int[curproblem.knownmaxima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    maxcnt[curindex] +=1;
	  }
	}
      }

      for (i=0;i<maxcnt.length;i++) {
	if (maxcnt[i]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }

  /** Calculate the number of found peaks. A peak is only found if at least 10%
      of the population is near it. */
  public double calcFoundMinimum()
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i;
      int popsize = population.length;
      SharingGAIndividual curind;
      int[] mincnt;
      NumericalOptimum curoptimum;
      int curindex;

      numberofpeaks = curproblem.knownmaxima.length + curproblem.knownminima.length;
      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;

      mincnt = new int[curproblem.knownminima.length];
      
      for (i=0;i<popsize;i++) {
	curind = population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (!curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    mincnt[curindex] +=1;
	  }
	}
      }

      for (i=0;i<mincnt.length;i++) {
	if (mincnt[i]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }

  /** Calculate the number of found top peaks. A peak is only found if at least 5%
      of the population is near it. */
  public double calcTopFoundMaximum(int peaks)
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i,j,k;
      int popsize = population.length;
      SharingGAIndividual curind;
      NumericalOptimum curoptimum;
      int curindex;
      NumericalOptimum[] optima;
      RKUVector tmpvec;

      if (peaks==0)
	numberofpeaks = curproblem.knownmaxima.length;
      else
	numberofpeaks = Math.min(peaks,curproblem.knownmaxima.length);

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;
      
      for (i=0;i<top5maxcnt.length;i++) {
	top5maxcnt[i] = 0;
      }

      for (i=0;i<popsize;i++) {
	curind = (SharingGAIndividual)population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    top5maxcnt[curindex] +=1;
	  }
	}
      }

      if (toppeaksmax==null) {
      	toppeaksmax = new int[numberofpeaks];
      }

      tmpvec = new RKUVector();
      tmpvec.addArray(curproblem.knownmaxima);
      tmpvec.quickSort(maximalpeaks);

      for (i=0;i<numberofpeaks;i++) {
	curoptimum = (NumericalOptimum)tmpvec.elementAt(i);
	toppeaksmax[i] = curoptimum.optimumindex;
      }

      for (i=0;i<toppeaksmax.length;i++) {
	if (top5maxcnt[toppeaksmax[i]]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }

  /** Calculate the number of found top peaks. A peak is only found if at least 5%
      of the population is near it. */
  public double calcTopFoundMinimum(int peaks)
    {
      double foundpeaks = 0;
      int numberofpeaks;
      int i,j,k;
      int popsize = population.length;
      SharingGAIndividual curind;
      NumericalOptimum curoptimum;
      int curindex;
      NumericalOptimum[] optimas;
      RKUVector tmpvec;

      if (peaks==0)
	numberofpeaks = curproblem.knownminima.length;
      else
	numberofpeaks = Math.min(peaks,curproblem.knownminima.length);

      // No peaks registered!!!
      if (numberofpeaks==0)
	return 0.0;
      
      for (i=0;i<top5mincnt.length;i++) {
	top5mincnt[i] = 0;
      }

      for (i=0;i<popsize;i++) {
	curind = (SharingGAIndividual)population[i];
	curoptimum = curproblem.getClosestFoundOptimum(curind.getPos());

	if (curoptimum!=null) {
	  if (!curoptimum.ismaximum) {
	    curindex = curoptimum.optimumindex;
	    top5mincnt[curindex] +=1;
	  }
	}
      }

      if (toppeaksmin==null) {
      	toppeaksmin = new int[numberofpeaks];
      }

      tmpvec = new RKUVector();
      tmpvec.addArray(curproblem.knownminima);
      tmpvec.quickSort(minimalpeaks);

      for (i=0;i<numberofpeaks;i++) {
	curoptimum = (NumericalOptimum)tmpvec.elementAt(i);
	toppeaksmin[i] = curoptimum.optimumindex;
	//	System.out.println("Peak "+toppeaksmin[i]+" fit="+curproblem.knownminima[toppeaksmin[i]].getFitness()+" psize="+top5mincnt[toppeaksmin[i]]);
      }

      for (i=0;i<toppeaksmin.length;i++) {
	if (top5mincnt[toppeaksmin[i]]>=findpercentage_threshold*popsize)
	  foundpeaks++;
      }

      return foundpeaks;
    }



  public boolean terminate()
    {
      return iteration<(maxiterations-1)*iterationmultiplier;
    }

  public void Framework_initialize_inner()
    {
      int i;
      population = new SharingGAIndividual[initialpopsize];

      currentdatasample = 0;

      for (i = 0;i<initialpopsize;i++) {
	population[i] = new SharingGAIndividual(this, true, theGA.representationtype);
      };

      ismaximization = curproblem.ismaximization;

      if (ismaximization) 
	bestdists = new double[curproblem.knownmaxima.length];
      else
	bestdists = new double[curproblem.knownminima.length];

      top5maxcnt = new int[curproblem.knownmaxima.length];
      top5mincnt = new int[curproblem.knownminima.length];

      results1 = null;
      if (savefitnessstats) {
	results1 = new SequenceTable("sharingfitness");
	results1.addColumn(new SequenceTableColumn("Generation"));
	results1.addColumn(new SequenceTableColumn("Bestfit"));
	results1.addColumns(curproblem.getSequenceTableColumns(""));
	results1.addColumn(new SequenceTableColumn("Mean"));
	results1.addColumn(new SequenceTableColumn("Std deviation"));
      }

      scoretable1 = null;
      if (savescorestats) {
	  scoretable1 = new SequenceTable("scores");
	  scoretable1.addColumn(new SequenceTableColumn("Generation"));
	  scoretable1.addColumn(new SequenceTableColumn("Evaluations"));
	  scoretable1.addColumn(new SequenceTableColumn("Score")); 
	  scoretable1.addColumn(new SequenceTableColumn("Top 5 Score")); 
	  scoretable1.addColumn(new SequenceTableColumn("# Peaks"));
	  scoretable1.addColumn(new SequenceTableColumn("# Top 5 Peaks"));
	  scoretable1.addColumn(new SequenceTableColumn("Best fit"));
      }	  

      disttable1 = null;
      if (savediststats) {
	  disttable1 = new SequenceTable("dists");
	  disttable1.addColumn(new SequenceTableColumn("Generation"));
	  disttable1.addColumn(new SequenceTableColumn("Evaluations"));
	  disttable1.addColumn(new SequenceTableColumn("Dist2global"));

	  if (ismaximization) {
	    for (i=0;i<curproblem.knownmaxima.length;i++) {
	      disttable1.addColumn(new SequenceTableColumn("DIST "+i));
	    }
	  }
	  else {
	    for (i=0;i<curproblem.knownminima.length;i++) {
	      disttable1.addColumn(new SequenceTableColumn("DIST "+i));
	    }
	  }
      }

      if (isdynamicproblem)
	((DynamicNumericalProblem)curproblem).resetProblem();

      if (savetablestats) {
	table_topfoundpeaks = 0;
	table_foundpeaks = 0;
	if (ismaximization)
	  table_bestfit = Double.NEGATIVE_INFINITY;
	else
	  table_bestfit = Double.POSITIVE_INFINITY;
      };


      // Calc iterationrounder
      if (iterationmultiplier == 1 || iterationmultiplier == 2 ||
	  iterationmultiplier == 5 || iterationmultiplier == 10) {
	iterationrounder = 1;
      }
      else if (iterationmultiplier == 3 || iterationmultiplier == 4 ||
	       iterationmultiplier == 9) {
	iterationrounder = 2;
      }
      else if (iterationmultiplier == 6 || iterationmultiplier == 7 ||
	       iterationmultiplier == 8) {
	iterationrounder = 3;
      }
      else {
	iterationrounder = 3;
      }

      evaluate();
    };

  /** BETA style inner call for summarize().
   */
  public void Framework_summarize_inner()
    {
      statistics();
    }



  RKUComparator coordsort = new  RKUComparator()
    {

      public int compare(Object o1, Object o2)
      {
	SharingGAIndividual ind1, ind2;
	double c1, c2;

	ind1 = (SharingGAIndividual)o1;
	ind2 = (SharingGAIndividual)o2;
	c1 = ((NumericalGenome)ind1.genome).getCoordinateValue(0);
	c2 = ((NumericalGenome)ind2.genome).getCoordinateValue(0);

	if (c1<c2)
	  return -1;
	else if (c1==c2)
	  return 0;
	else
	  return 1;
      }
    };


  /** Override this in your implementation. */
  public void selection()
    {
      SharingGAIndividual[] newpop = new SharingGAIndividual[initialpopsize];
      double sharingfactor, dist;
      int i, j;
      double[] thispos, otherpos;
      double xdist;

      // Sort on first coordinate
      Arrays.sort(population,coordsort);

      for (i = 0;i<population.length;i++) {
	sharingfactor = 0;
	thispos = population[i].getPos();

	sharingfactor += 1 - Math.pow(0/sigma_share, alpha);

	// Calc for individuals to the "left"
	j=i-1;
	xdist = 0;
	while (xdist<sigma_share && j>=0) {
	  otherpos = population[j].getPos();
	  xdist = Math.abs(thispos[0] - otherpos[0]);

	  if (xdist<sigma_share) {
	    dist = RKUGeometry.distancePoint2Point(thispos, otherpos);
	    if (dist<sigma_share)
	      sharingfactor += 1 - Math.pow(dist/sigma_share, alpha);
	  }
	  j--;
	}

	// Calc for individuals to the "right"
	j=i+1;
	xdist = 0;
	while (xdist<sigma_share && j<population.length) {
	  otherpos = population[j].getPos();
	  xdist = Math.abs(thispos[0] - otherpos[0]);

	  if (xdist<sigma_share) {
	    dist = RKUGeometry.distancePoint2Point(thispos, otherpos);
	    if (dist<sigma_share)
	      sharingfactor += 1 - Math.pow(dist/sigma_share, alpha);
	  }
	  j++;
	}

	if (ismaximization) 
	  population[i].fitnessvalue = population[i].getFitness()/sharingfactor;
	else
	  population[i].fitnessvalue = population[i].getFitness()*sharingfactor;

	//	System.out.println(population[i].fitnessvalue+" fit="+population[i].getFitness()+"  sf="+sharingfactor);
      }

      TournamentSelection.selectInto(population, initialpopsize, ismaximization, true, newpop);
      population = newpop;
    };

  SharingGAIndividual[] parents = new SharingGAIndividual[2];

  /* Perform crossover on nations. */
  public void recombine()
    {
      int i;
      SharingGAIndividual[] newpop;
      newpop = new SharingGAIndividual[initialpopsize];

      for (i = 0;i<initialpopsize;i++) {
	if (UsefulRoutines.randomBiasedBoolean(p_c)) {
	  RandomSelection.selectInto(population, 2, ismaximization, false, parents);
	  newpop[i] = parents[0].crossover(parents[0], parents[1]);
	}
	else
	  newpop[i] = (SharingGAIndividual)population[i].clone();
      }
      population = newpop;
    }

  /** Mutate all individuals. */
  public void alter()
    {
      int i;
      double curmut;

      if (!isdynamicproblem) {
	curmut = 1.0/(Math.pow((double)iteration,0.75));
      }
      else {
	curmut = mutationvariance;
      }

      for (i = 0; i<initialpopsize;i++) {
	population[i].mutate(p_m, curmut);
      }
    } 

  /** Evaluate all individuals. */
  public void evaluate()
    {
      double fitsum;
      int i;

      fitsum = 0;

      for (i = 0; i<initialpopsize;i++) {
	fitsum += population[i].getFitness();
      }
      //	System.out.println("Fitsum = "+fitsum);
    }

  SharingGAIndividual eliteIndividual;

  public void preserveElite()
    {
      if (elitism) {
	eliteIndividual = (SharingGAIndividual)(population[PopulationMeasurements.indexOfBest(population, ismaximization)]).clone();
      }
    }

  public void keepElite()
    {
      int pos;
      if (elitism) {
	pos = RKURandom.randomInt(population.length);
	population[pos] = eliteIndividual;
      }
    }


  // **** BatchJob implementation *****************************

  /** Set the settings for the algorithm. The passed hashtable contains
      only String objects which are all related to the input file given 
      to the scheduler. 
  */
  public void setSettings(Hashtable settings)
    {
      String curstr;
      NumericalProblem lcurproblem = null;

      if ((curstr = (String)settings.get("verbose"))!=null) {
	verbose = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savefitnessstats"))!=null) {
	savefitnessstats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savescorestats"))!=null) {
	savescorestats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savediststats"))!=null) {
	savediststats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("savetablestats"))!=null) {
	savetablestats = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("elitism"))!=null) {
	elitism = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("datasampling"))!=null) {
	datasampling = (new Double(curstr)).intValue();
      }

      if( (curstr = (String)settings.get("p_m"))!=null) {
	p_m = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("mutationvariance"))!=null) {
	mutationvariance = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("p_c"))!=null) {
	p_c = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("sigma_share"))!=null) {
	sigma_share = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("alpha"))!=null) {
	alpha = (new Double(curstr)).doubleValue();
      }

      if ((curstr = (String)settings.get("maxiterations"))!=null) {
	maxiterations = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("initialpopsize"))!=null) {
	initialpopsize = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("iterationmultiplier"))!=null) {
	iterationmultiplier = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("bitspervar"))!=null) {
	bitspervar = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("displaygraph"))!=null) {
	displaygraph = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("problemname"))!=null) {
	lcurproblem = NumericalProblemSelector.selectProblem(curstr);
      }
      else {
	lcurproblem = curproblem;
      }

      if (lcurproblem!=null && lcurproblem instanceof DynamicNumericalProblem) {
	isdynamicproblem = true;
	((DynamicNumericalProblem)lcurproblem).setSettings(settings, this);
      }
      else
	isdynamicproblem = false;

      theGA.curproblem = lcurproblem;
      setProblem(lcurproblem);
      curproblem = lcurproblem;

      if (curproblem.dimensions==2 && ((curstr = (String)settings.get("displaybest"))!=null)) {
	displaybest = (new Integer(curstr)).intValue();
      }

      // Set the number of bits per variable
      setBitsPerVariable(bitspervar);

    };

  /** Get the default settings in the BatchJobScheduler format. This 
      method can be used to reconstruct an input file for the scheduler. 
  */
  public String getDefaultSettings()
    {
      return "";
    };

  /** Initialize a batchjob. This is called once before any run is performed.
   */
  public void initializeBatchJobs()
    {
    };

  /** Finalize a batchjob. This is called once after all runs are performed.
   */
  public void finalizeBatchJobs()
    {
    };

  /** Initialize a run series. This is called once before the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void initializeRunSeries()
    {};

  /** Finalize a run series. This is called once after the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void finalizeRunSeries()
    {};

  /** Initialize and start a single run of the algorithm. You can 
      usually just call doEA() from your framework.
  */
  public void initializeAndStartRun()
    {
      doEA();
    };

  /** Finalize the single run of the algorithm. This is called immediately
      after the initializeAndStartRun(). It can be used to reset 
      measurements, increase counters, etc.
  */
  public void finalizeRun()
    {
    };

  /** Get the run data as text. Your implementation must return
      an array of objects that each implements the interface ConvertToText from the package
      EA.recording. You can use the classes found in EA.recording or 
      implement your own classes.
      @see EA.recording.ResultSet
      @see EA.recording.Measurement
      @see EA.recording.ConvertToText
  */
  public Object[] getDataAsText()
    {
      Object[] res;
      RKUVector resvec= new RKUVector();

      if (savefitnessstats) {
	resvec.addElement(results1);
      }

      if (savescorestats) {
	resvec.addElement(scoretable1);
      }

      if (savediststats) {
	resvec.addElement(disttable1);
      }

      if (savetablestats) {
	SequenceTable tabletable1 = new SequenceTable("table");
	tabletable1.addColumn(new SequenceTableColumn("Bestfit"));
	tabletable1.addColumn(new SequenceTableColumn("Found peaks"));
	tabletable1.addColumn(new SequenceTableColumn("Top 5 found"));
	tabletable1.initializeRow();

	tabletable1.updateLastRow(0, table_bestfit);
	tabletable1.updateLastRow(1, table_foundpeaks);
	tabletable1.updateLastRow(2, table_topfoundpeaks);

	resvec.addElement(tabletable1);
      }

      res = resvec.toArray();
      return res;
    };

  // ************* Plot interface **********************************

  /** Extract the data as a 2 dimensional array of objects. <br>
      <b>Note:</b> All second-indexes arrays must have equal length.
  */
  public Object[][] extract2DAsObjects(int plotternumber)
    {
      Object[][] res = new Object[2][0];
      switch (plotternumber) {
      case 0:
	res[0] = (results1.getColumn(1)).getDataAsArray();
	res[1] = (results1.getColumn(2+curproblem.dimensions)).getDataAsArray();
	break;
      case 1:
	res[0] = (results1.getColumn(2)).getDataAsArray();
	res[1] = (results1.getColumn(3)).getDataAsArray();
	break;
      }	    
      return res;
    };

  /** Extract the data as a 2 dimensional array of doubles.<br>
      <b>Note:</b> All second-indexes arrays must have equal length. */
  public double[][] extract2DAsDoubles(int plotternumber)
    {
      return null;
    };

  int[][] resultstypes = {{0,0},{0,0}};
  int[][] trajectorytypes = {{2,0},{2,0}};

  public int[][] extract2DDataTypes(int plotternumber)
    {
      switch(plotternumber)
	{
	case 0:
	  return resultstypes;
	case 1: 
	  return trajectorytypes;
	}
      return resultstypes;
    };

  /** Extract the name of a graph given an index. */
  public String extract2DName(int index, int plotternumber)
    {
      switch (plotternumber) {
      case 0:
	switch(index) {
	case 0:
	  return "Bestfit";
	case 1:
	  return "Mean";
	}
	break;
      case 1:
	return "Best pos";
      }
      return "";
    };


}





class SharingGAIndividual extends Individual implements RKUCloneable, RKUValuation, NumericalInspector
{
      double fitnessvalue = 0;


  /** Create a new SharingGAIndividual. 
      @param frame The framework for this individual.
      @param initialize True if you want to create a new Bit/Real-NumericalGenome.
      @param reptype The type of representation.
  */
  public SharingGAIndividual(NumericalFramework frame, boolean initialize, int reptype)
    {
      super(frame);

      if (initialize) {
	switch(reptype) {
	case 0:
	  genome = new RealNumericalGenome((RealNumericalFramework)frame,true);
	  break;
	case 1:
	  genome = new BitNumericalGenome((BitNumericalFramework)frame,true);
	  break;
	}
      }
    }

  public static SharingGAIndividual crossover(SharingGAIndividual individual1, SharingGAIndividual individual2)
    {
      SharingGAIndividual res;

      res = new SharingGAIndividual((NumericalFramework)individual1.framework, false, 0);

      if (individual1.genome instanceof RealNumericalGenome) {
	res.genome = RealNumericalGenome.crossover(individual1.genome, individual2.genome);
      }
      else if (individual1.genome instanceof BitNumericalGenome) {
	res.genome = BitNumericalGenome.crossover(individual1.genome, individual2.genome);
      };
      return res;
    };

  public double getFitness()
    {
      return ((NumericalFitness)((NumericalFramework)framework).fitnessfunction).calcFitness(((NumericalGenome)genome).getPos());
    }

  public Object clone()
    {
      SharingGAIndividual res;

      res = new SharingGAIndividual((NumericalFramework)framework, false, 0);
      res.genome = (Genome)(this.genome.clone());
      return res;
    }


  public double value()
    {
      return fitnessvalue;
    }

  public double[] getPos()
    {
      return ((NumericalGenome)genome).getPos();
    }

  /** Mutate the individuals genome with a certain variance. */
  public void mutate(double p_m, double var)
    {
      if (this.genome instanceof RealNumericalGenome) {      
	((RealNumericalGenome)genome).mutate(p_m, var);
      }
      else {
	((RealNumericalGenome)genome).mutate(p_m);
      }
    }


  // Inteface-implementation: NumericalInspector
  public double[] inspectGetPos() { return getPos(); }
  public double inspectGetFitness() { return getFitness(); }

}
